home *** CD-ROM | disk | FTP | other *** search
- // CNTRL5.CPP - "driver" function for RARS - M. Timin, Dec. 1994
- // adapted to ver. 0.39 3/6/95 by M. Timin
-
- #include <string.h>
- #include <stdlib.h>
- #include <math.h>
- #include "car.h"
-
- extern char* glob_name; // The name string, below, will be copied here
- extern const double CARWID; // car width, feet
-
- // The task of this function is to compute vc and alpha. To understand
- // vc and alpha, remember that in this model, the wheels are always slipping,
- // at least a little. (Think of a cinder track.) vc is the speed
- // of the bottom of the wheel relative to the car. (Velocity Commanded)
- // If the car is coasting at zero power then vc == s.v, the speed of the
- // car. If vc is held constant for a while the cars speed will approach
- // vc, unless it is cornering, in which case vc may greatly exceed the
- // speed. The angle "alpha" is the angle between the car's orientation angle
- // and its velocity vector. (like angle of attack of an aircraft)
- // Cornering force depends on alpha. (It is also thought of as a slip angle.)
- // (alpha is not directly related to the steering wheel angle, which is not
- // modeled here, and is assumed to rapidly oscillate about alpha to keep the
- // car under control, and acheive the desired alpha.)
- con_vec cntrl5(situation s)
- {
- const char name[] = "Stroust"; // This is the robot driver's name!
- static int init_flag = 1; // cleared by first call
- // A "lane" is just a preferred distance from the wall of the track.
- double width; // track width, feet
- static double lane = 90; // determines right-left position on straightaway
- static int lane_time = 0; // counts time when not in normal lane
- con_vec result; // This is what is returned.
- const double normalane = 0.0; // usual position down the straight
- const double steer_gain = .18; // servo parameters on the straight:
- const double steer_damp = .3;
- static double ex_pwr_count = 0; // counts calls when power_req > 1
- double corn_speed; // target speed for cornering, ft/sec
- double corn_next; // target speed for next corner
- const double std_corner = 58.0; // cornering speed for 100 ft. radius turn
- double alpha, vc; // components of result
-
- if(init_flag) { // first time through, only copy name:
- strcpy(glob_name, name);
- init_flag = 0;
- result.alpha = result.vc = 0;
- return result;
- }
-
- if(stuck(s.backward, s.v,s.vn, s.to_lft,s.to_rgt, &result.alpha,&result.vc))
- return result;
-
- width = s.to_lft + s.to_rgt; // find width of track
- // compute a cornering speed proportional to square root of current radius:
- if(s.cur_rad > 0.0)
- corn_speed = std_corner * sqrt((s.cur_rad+.5*width)/150.0);
- else if(s.cur_rad < 0.0)
- corn_speed = std_corner * sqrt((.5*width-s.cur_rad)/150.0);
- else corn_speed = 2 * std_corner;
-
- // compute a cornering speed for the next corner:
- if(s.nex_rad > 0.0)
- corn_next = std_corner * sqrt((s.nex_rad+.5*width)/150.0);
- else if(s.nex_rad < 0.0)
- corn_next = std_corner * sqrt((.5*width-s.nex_rad)/150.0);
- else corn_next = 2 * std_corner;
-
- // maybe choose a different lane: (to help in passing)
- if(!s.dead_ahead) {
- if(lane_time <= 0) {
- lane = normalane;
- lane_time = 0;
- }
- }
- else if(!lane_time) {
- // pick a different lane:
- if(lane >= 80) // pick a new lane somehow:
- lane = random(60) - 20;
- else if(lane <= -80)
- lane = 20 - random(60);
- else
- lane = random(180) - 90;
- lane_time = 160; // we will stay in the new lane this long
- }
- if(lane_time > 0)
- --lane_time;
-
- // set alpha based on a servo-mechanism approach, trying to maintain
- // a certain distance from the track wall:
- if(s.cur_rad == 0) { // If we are on the straightaway:
- // alpha is proportional to lane error:
- alpha = .35 * steer_gain * (s.to_lft - s.to_rgt - lane) / width;
- if(s.dead_ahead) // Change lanes quicker if someone in front:
- alpha *= 2.0;
- }
- else if(s.cur_rad > 0) { // in the turn, stick close to the inside:
- alpha = steer_gain * (3 * (s.to_lft-s.to_rgt) / width);
- if(s.dead_ahead) // if someone ahead, reduce alpha to pass on outside
- alpha *= .8;
- }
- else { // this is for right turns, similar to above
- alpha = -steer_gain * (3 * (s.to_rgt-s.to_lft) / width);
- if(s.dead_ahead)
- alpha *= .8;
- }
- alpha -= steer_damp * s.vn / s.v; // This is damping, to prevent oscillation
-
- // If we are on a straightaway:
- if(s.cur_rad == 0 || s.cur_rad < -600.0 || s.cur_rad > 600.0)
- if(s.to_end/s.cur_len > .28) // if we are far from the end:
- vc = s.v + 90/s.v; // keep accellerating near full power
- else { // otherwise,
- vc = (corn_next + 4.0 * s.v)/5.0; // ready for next corner
- if(s.dead_ahead) // cut if someone's dead ahead!
- alpha *= 2.0;
- }
- else { // If we're in the curve, maintain speed.
- if(s.to_end > .7)
- vc = (corn_speed + 3.0 * s.v) / 4.0;
- else
- vc = (.5 * (corn_speed+corn_next) + 3 * s.v) / 4.0;
- }
-
- // If last time we requested more power than is available, make
- // vc closer to s.v to reduce requested power
- if(s.power_req > 1.0)
- ++ex_pwr_count; // count how many times we want too much power
- else if(ex_pwr_count > 0) // we decrement this to zero if s.power_req < 1
- --ex_pwr_count;
- if(ex_pwr_count > 0)
- // Compute a weighted average of vc (as computed above) and s.v:
- vc = (ex_pwr_count * s.v + 2 * vc)/(2 + ex_pwr_count);
-
- result.vc = vc; result.alpha = alpha;
- return result;
- }
-